package wsi.task.input;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import org.rygh.core.html.table.HtmlTable;
import org.rygh.core.html.table.TableData;
import org.rygh.core.html.table.TableTuple;
import org.rygh.core.model.common.MapSet;
import org.rygh.core.model.common.StringSet;
import org.rygh.semantic.gui.swing.input.Input;

import wsi.dataguide.tree.WSXmlLeaf;
import wsi.dataguide.tree.WSXmlTree;
import wsi.task.TaskRoutine;

public class InputLocator extends TaskRoutine {
	private final boolean isDataGuide;
	private final WSXmlTree tree;
	private final List<InputLocation> locations = new ArrayList<>();
	private Input input;

	public InputLocator(WSXmlTree tree, boolean isDataGuide) {
		super(null);

		this.tree = tree;
		this.isDataGuide = isDataGuide;
	}

	@Override
	public void compute() {
		locate2(tree.getAllLeaves());

	}

	public List<InputLocation> getLocations() {
		return locations;
	}

	/**
	 * if a tuple from values contains at least on word of input, then it is
	 * identified as similar.
	 * 
	 * @param values
	 * @return
	 */
	private double getSimilarity(Input input_value, Collection<String> values) {
		StringSet input_set = new StringSet(input_value.getValue());
		StringSet _set;

		int size = 0;

		for (String i : values) {
			_set = new StringSet(i);

			if (_set.containsAtLeastOne(input_set))
				size++;
		}

		return 1. * size / values.size();
	}

	private boolean isExactMatch(Input input_value, Collection<String> values) {

		StringSet input_set = new StringSet(input_value.getValue());
		StringSet _set;

		if (input_set.isEmpty())
			return false;

		boolean found = false;

		for (String i : values) {
			_set = new StringSet(i);

			if (input_set.equals(_set)) {
				found = true;
				break;
			}

		}

		return found;
	}

	private boolean isInput(Input input_value, Collection<String> values) {

		StringSet input_set = new StringSet(input_value.getValue());
		StringSet _set;

		assert !input_set.isEmpty();

		boolean found = false;

		// System.out.println("\ninput " + input);
		// System.out.println("\nset 1 " + set1);

		for (String i : values) {
			_set = new StringSet(i);

			if (input_set.equals(_set)) {
				found = true;
				break;
			}

			if (_set.contains(input_set)) {
				found = true;
				break;
			}

			// System.out.println("set 2 " + set2);

		}

		return found;
	}

	private void locate2(List<WSXmlLeaf> leaves) {
		for (WSXmlLeaf i : leaves) {

			// log.info("locating at " + node.getObject().getName());

			InputLocation loc;

			if (isDataGuide) {
				MapSet<Input, String> map = i.getValue().getValueMap();

				for (Entry<Input, Set<String>> j : map.entrySet()) {
					Input input_value = j.getKey();
					Set<String> values = j.getValue();

					if (isInput(input_value, values)) {
						log.info(String.format("found input for %s at %s",
								input_value, i.getValue().getName()));
						loc = new InputLocation(i);
						loc.setInput(input_value);
						loc.setExactMatch(isExactMatch(input_value, values));
						loc.setSimilarity(getSimilarity(input_value, values));

						locations.add(loc);
					}

				}
			} else {
				Input value = new Input(i.getValue().getValue());
				List<String> l = new ArrayList<>();
				l.add(input.getValue());

				if (!value.getValue().trim().isEmpty()) {

					if (isExactMatch(value, l)) {
						log.info(String.format("found input for %s at %s",
								value, i.getValue().getName()));
						loc = new InputLocation(i);
						loc.setInput(input);
						loc.setExactMatch(true);
						loc.setSimilarity(getSimilarity(value, l));

						locations.add(loc);
					}
				}
			}
		}
	}

	@Override
	public String save() {
		// UIo.saveFile(new File(dir.getFunctionDir(),
		// "dataguides_location.txt")
		// .getAbsolutePath(), toString());

		//

		// UIo.saveFile(
		// new File(dir.getDataGuidesDir(), String.format(
		// "%s_%s_location.txt", serviceName, function.getName()))
		// .getAbsolutePath(), toString());

		return "";
	}

	public void setInput(Input input) {
		this.input = input;
	}

	public HtmlTable toHtmlTable() {
		TableData valueList = new TableData();
		TableTuple tuple = new TableTuple();

		tuple.add("Tag");
		tuple.add("Input");
		tuple.add("Match");
		tuple.add("Similarity");
		tuple.add("XPath");

		valueList.add(tuple);

		for (InputLocation i : locations)
			valueList.add(i.getCells());

		return new HtmlTable(input.getValue(), valueList);
	}

	@Override
	public String toString() {
		StringBuilder sbuilder = new StringBuilder();

		for (InputLocation i : locations) {
			sbuilder.append(i);
			sbuilder.append("\r\n");
		}

		return sbuilder.toString();
	}
}
